package com.company.graphgetter;

import com.company.TrianglePacket;
import com.company.graph.NodeGraph;
import com.company.logger.GetterLogger;

import java.util.*;

public class NodeGetterWithGraph implements GraphGetter {
    NodeGraph G;
    HashSet<Integer> marked;
    HashMap<Integer, Integer> countRecorder;
    List<TrianglePacket> triangleRankList;
    int counter = 0;

    public NodeGetterWithGraph(NodeGraph graph) {
        G = graph;
        marked = new HashSet<>();
        countRecorder = new HashMap<>();
        triangleRankList = new ArrayList<>();
        int top = 0;
        int bottom = G.adjs().size();
        GetterLogger getterLogger = new GetterLogger();
        for (Map.Entry<Integer, HashSet<Integer>> entry : G.adjs().entrySet()) {
            Integer v = entry.getKey();
            HashSet<Integer> wSet = entry.getValue();
            top++;
            float progress = ((float) top) / bottom * 100;
            getterLogger.log(progress);
            for (Integer w : wSet) {
                for (Integer p : G.adj(w)) {
                    if (G.hasEdge(v, p)) {
                        //发现v - w - p 构成的三角形
                        int cp = countRecorder.getOrDefault(p, 0);
                        int cw = countRecorder.getOrDefault(w, 0);
                        int cv = countRecorder.getOrDefault(v, 0);
                        cp++;
                        cw++;
                        cv++;
                        countRecorder.put(p, cp);
                        countRecorder.put(w, cw);
                        countRecorder.put(v, cv);
                        counter++;
                    }
                }
            }
        }
        for (Map.Entry<Integer, Integer> entry : countRecorder.entrySet()) {
            Integer key = entry.getKey();
            Integer count = entry.getValue();
            count /= 6;
            countRecorder.put(key, count);
            triangleRankList.add(new TrianglePacket(key, count));
        }
        //按照持有三角形个数 对结点进行排序
        Collections.sort(triangleRankList);
        counter /= 6;
    }

    /**
     * 取得图中三角形总数
     */
    public int getTotalTriangle() {
        return counter;
    }

    /**
     * 取得某个结点的三角形个数
     *
     * @param id 结点id
     */
    public int getTriangle(int id) {
        return countRecorder.getOrDefault(id, 0);
    }

    /**
     * 按照结点所持有的三角形个数 从高到低排序
     */
    public List<TrianglePacket> ranks() {
        return triangleRankList;
    }

    /**
     * 删除 “v和w之间的边” 会触发这个函数来刷新局部统计的三角形的个数
     */
    public void refreshPartialTriangle(int v, int w) {
        List<Integer> commonNeighbors = new LinkedList<>();
        Set<Integer> set = new HashSet<>();
        for (Integer p : G.adj(v)) {
            set.add(p);
        }
        for (Integer p : G.adj(w)) {
            if (set.contains(p)) {
                commonNeighbors.add(p);
            }
        }
        commonNeighbors.add(v);
        commonNeighbors.add(w);
        for (Integer p : commonNeighbors) {
            HashSet<Integer> wSet = G.adj(p);
            int count = 0;
            for (Integer pw : wSet) {
                for (Integer pp : G.adj(pw)) {
                    if (wSet.contains(pp)) {
                        count++;
                    }
                }
            }
            count /= 2;
            countRecorder.put(p, count);
        }
    }

    /**
     * 取得当前三角形个数最大的结点
     */
    public TrianglePacket getTopRank() {
        int maxCount = 0;
        int id = -1;
        TrianglePacket packet;
        for (Map.Entry<Integer, Integer> entry : countRecorder.entrySet()) {
            Integer count = entry.getValue();
            if (count > maxCount) {
                id = entry.getKey();
                maxCount = count;
            }
        }
        packet = new TrianglePacket(id, maxCount);
        return packet;
    }

    /**
     * w结点是 v结点的 邻接边
     * 得到拥有三角形数最多的 v - w
     * 并将w作为返回值
     */
    public int getMaxTriangleEdgeNeighbor(int v) {
        HashSet<Integer> wSet = G.adj(v);
        int maxTriangle = 0;
        int maxWid = -1;
        for (Integer w : wSet) {
            int count = 0;
            for (Integer p : G.adj(w)) {
                if (p == w || p == v || !wSet.contains(p)) {
                    continue;
                }
                count++;
            }
            if (count > maxTriangle) {
                maxTriangle = count;
                maxWid = w;
            }
        }
        return maxWid;
    }

    @Override
    public String result() {
        StringBuilder sb = new StringBuilder();
        String str;
        str = "'最大'顶点三角个数'：" + triangleRankList.get(0) + "\n";
        sb.append(str);
        str = "'最小'顶点三角个数'：" + triangleRankList.get(triangleRankList.size() - 1) + "\n";
        sb.append(str);
        str = "'三角形个数'：" + getTotalTriangle() + "\n";
        sb.append(str);
        return sb.toString();
    }

    public Integer zeroCount() {
        return G.nodeLength() - ranks().size();
    }
}
